import React from 'react';
import PropTypes from 'prop-types';

import style from 'PVWStyle/ReactWidgets/ColorByWidget.mcss';

import AdvancedView from './AdvancedView';

const SEP = ':|:';

function doubleToHex(number) {
  let str = Math.floor(number * 255).toString(16);
  while (str.length < 2) {
    str = `0${str}`;
  }
  return str;
}

export default class ColorByWidget extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      advancedView: false,
      colorValue: SEP,
      colorValues: [],
      representationValue: '',
      representationValues: [],
      scalarBarVisible: false,
      solidColor: '#fff',
    };

    // Bind callback
    this.onRepresentationChange = this.onRepresentationChange.bind(this);
    this.onColorChange = this.onColorChange.bind(this);
    this.updateState = this.updateState.bind(this);
    this.toggleScalarBar = this.toggleScalarBar.bind(this);
    this.toggleAdvancedView = this.toggleAdvancedView.bind(this);
  }

  componentWillMount() {
    this.updateState(this.props);
  }

  componentWillReceiveProps(nextProps) {
    this.updateState(nextProps);
  }

  onRepresentationChange(event) {
    const representationValue = event.target.value;
    this.setState({ representationValue });
    if (this.props.onChange) {
      this.props.onChange({
        type: 'propertyChange',
        changeSet: [
          {
            id: this.props.representation.id,
            name: 'Representation',
            value: representationValue,
          },
        ],
      });
    }
  }

  onColorChange(event) {
    let scalarBarVisible = this.state.scalarBarVisible;
    const colorValue = event.target.value;
    const [arrayLocation, arrayName] = colorValue.split(SEP);
    const colorMode = arrayName ? 'array' : 'SOLID';
    const vectorMode = 'Magnitude';
    const vectorComponent = 0;
    const rescale = false;

    if (colorMode === 'SOLID') {
      scalarBarVisible = false;
    }

    this.setState({ colorValue, scalarBarVisible, colorMode });
    if (this.props.onChange) {
      this.props.onChange({
        type: 'colorBy',
        representation: this.props.representation.id,
        arrayLocation,
        arrayName,
        colorMode,
        vectorMode,
        vectorComponent,
        rescale,
      });
    }
  }

  updateState(props) {
    if (!props.source || !props.representation) {
      return;
    }

    const extractRepProp = (p) => p.name === 'Representation';
    const removeFieldArray = (a) => a.location !== 'FIELDS';
    const representationValues = props.representation.ui.filter(
      extractRepProp
    )[0].values;
    const representationValue = props.representation.properties.filter(
      extractRepProp
    )[0].value;
    const colorValues = [{ name: 'Solid color' }].concat(
      props.source.data.arrays.filter(removeFieldArray)
    );
    const colorValue = props.representation.colorBy.array
      .filter((v, i) => i < 2)
      .join(SEP);
    const scalarBarVisible = !!props.representation.colorBy.scalarBar;
    const solidColor = `#${props.representation.colorBy.color
      .map(doubleToHex)
      .join('')}`;

    const colorMode = colorValue.split(SEP)[1] ? 'array' : 'SOLID';

    this.setState({
      representationValues,
      representationValue,
      colorValues,
      colorValue,
      scalarBarVisible,
      solidColor,
      colorMode,
    });
  }

  toggleScalarBar() {
    let scalarBarVisible = !this.state.scalarBarVisible;

    if (this.state.colorMode === 'SOLID') {
      scalarBarVisible = false;
    }

    this.setState({ scalarBarVisible });
    if (this.props.onChange) {
      this.props.onChange({
        type: 'scalarBar',
        source: this.props.source.id,
        representation: this.props.representation.id,
        visible: scalarBarVisible,
      });
    }
  }

  toggleAdvancedView() {
    const advancedView = !this.state.advancedView;
    this.setState({ advancedView });
  }

  render() {
    if (!this.props.source || !this.props.representation) {
      return null;
    }

    return (
      <div className={[style.container, this.props.className].join(' ')}>
        <div className={style.line}>
          <i className={style.representationIcon} />
          <select
            className={style.input}
            value={this.state.representationValue}
            onChange={this.onRepresentationChange}
          >
            {this.state.representationValues.map((v, idx) => (
              <option key={idx} value={v}>
                {v}
              </option>
            ))}
          </select>
        </div>
        <div className={style.line}>
          <i className={style.colorIcon} />
          <select
            className={style.input}
            value={this.state.colorValue}
            onChange={this.onColorChange}
          >
            {this.state.colorValues.map((c, idx) => (
              <option
                key={idx}
                value={c.location ? [c.location, c.name].join(SEP) : ''}
              >
                {c.location
                  ? `(${c.location === 'POINTS' ? 'p' : 'c'}${c.size}) ${
                      c.name
                    }`
                  : c.name}
              </option>
            ))}
          </select>
        </div>
        <div className={style.line}>
          <i
            onClick={this.toggleAdvancedView}
            className={
              this.state.advancedView
                ? style.advanceIconOn
                : style.advanceIconOff
            }
          />
          {this.props.scalarBar &&
          this.state.colorValue &&
          this.state.colorValue.split(SEP)[1].length ? (
            <img
              onClick={this.toggleScalarBar}
              className={style.scalarBar}
              src={`data:image/png;base64,${this.props.scalarBar}`}
              alt="ScalarBar"
            />
          ) : (
            <div
              className={style.scalarBar}
              style={{ backgroundColor: this.state.solidColor }}
            />
          )}
          <i
            onClick={this.toggleScalarBar}
            className={
              this.state.scalarBarVisible
                ? style.scalarBarIconOn
                : style.scalarBarIconOff
            }
          />
        </div>
        <AdvancedView visible={this.state.advancedView} {...this.props} />
      </div>
    );
  }
}

ColorByWidget.propTypes = {
  className: PropTypes.string,
  max: PropTypes.number,
  min: PropTypes.number,
  onChange: PropTypes.func,
  presets: PropTypes.object,
  representation: PropTypes.object,
  scalarBar: PropTypes.string,
  source: PropTypes.object,
  opacityPoints: PropTypes.array,
  onOpacityPointsChange: PropTypes.func,
  opacityEditorSize: PropTypes.array,
  useGaussian: PropTypes.bool,
  gaussians: PropTypes.array,
};

ColorByWidget.defaultProps = {
  className: '',
  useGaussian: false,
  min: 0,
  max: 1,
  gaussians: undefined,
  onChange: undefined,
  presets: undefined,
  representation: undefined,
  scalarBar: undefined,
  source: undefined,
  opacityPoints: undefined,
  onOpacityPointsChange: undefined,
  opacityEditorSize: undefined,
};
